package scanner

import (
	"errors"
	"io/ioutil"
	"learning/gooop/spring/autogen/common"
	"learning/gooop/spring/autogen/domain"
	"os"
	"path"
	"strings"
)

type IProjectScanner interface {
	ScanProject(name, dir string) (error, *domain.ProjectInfo)
}

type tProjectScanner int

func (me *tProjectScanner) ScanProject(name, dir string) (error, *domain.ProjectInfo) {
	e, module := me.parseModFileAndGetModuleName(dir)
	if e != nil {
		return e, nil
	}

	files, e := ioutil.ReadDir(dir)
	if e != nil {
		return e, nil
	}

	project := domain.NewProjectInfo()
	project.Name = name
	project.LocalDir = dir
	project.Module = module

	for _, file := range files {
		if !file.IsDir() {
			continue
		}

		e, pkg := DefaultPackageScanner.ScanPackage(project, nil, dir+"/"+file.Name())
		if e != nil {
			return e, nil
		} else {
			project.AppendPackage(pkg)
		}
	}

	return nil, project
}

func (me *tProjectScanner) parseModFileAndGetModuleName(dir string) (error, string) {
	modfile := path.Join(dir, gModuleFile)
	_, e := os.Stat(modfile)
	if e != nil {
		return gErrorModuleFileNotFound, ""
	}

	data, e := ioutil.ReadFile(modfile)
	if e != nil {
		return e, ""
	}

	text := string(data)
	for _, line := range strings.Split(text, "\n") {
		line := strings.TrimSpace(line)
		if !common.Tokens.MatchString(line, gModulePrefix) {
			continue
		}

		if ok, s := common.Tokens.MatchRegexp(line, gModulePattern); ok {
			return nil, strings.TrimSpace(s[len(gModulePrefix)+1:])
		}
	}

	return gErrorProjectModuleNotFound, ""
}

var gModuleFile = "go.mod"
var gModulePrefix = "module"
var gModulePattern = "^module\\s+\\w+(/\\w+)*"

var gErrorModuleFileNotFound = errors.New("module file not found: go.mod")
var gErrorProjectModuleNotFound = errors.New("project module not found in go.mod")

var DefaultProjectScanner IProjectScanner = new(tProjectScanner)
